/**
 * @file sysfile.c
 * @date 23.05.01
 * @author xin
 * @brief 与文件相关的具体系统调用函数
 * @version 0.1
 * @status Stable
*/

#include "types.h"
#include "param.h"
#include "proc.h"
#include "defs.h"
#include "fs.h"
#include "file.h"

/**
 * @brief 获取第n个word对齐的系统调用参数并将其作为一个文件描述符
 *        返回文件描述符以及相应的文件结构体
 * @param n 第n个参数
 * @param pfd 存储文件描述符的指针
 * @param pf 存储文件结构体指针的指针
 * @return 0:success    -1:failure
*/
static int
argfd(int n, int *pfd, struct file **pf)
{
    int fd;
    struct file *f;

    argint(n, &fd);
    if (fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0)
        return -1;  // 描述符不合法或当前进程包含的fd对应的文件地址为空
    if (pfd)    // 如果pfd不为0说明需要存储文件描述符
        *pfd = fd;
    if (pf)     // 如果pf不为0说明需要存储文件结构体
        *pf = f;
    return 0;
}

/**
 * @brief write系统调用
 * @return 写入文件字节数，若失败返回-1
*/
uint64
sys_write(void)
{
    struct file *f; // 要写入的文件
    int n;          // 写入的字节数
    uint64 p;       // 要写入的字符

    argaddr(1, &p);
    argint(2, &n);
    printf("%c", p);
    if (argfd(0, 0, &f) < 0)
        return -1;
    return filewrite(f, p, n);
}

/**
 * @brief exec系统调用，携带trapframe中的参数执行参数中的文件
 * @return 返回exec返回的参数个数，若出现错误返回-1
*/
uint64
sys_exec(void)
{
    // 执行文件的路径、携带参数
    char path[MAXPATH], *argv[MAXARG];
    int i;
    // argv[]地址、获取到的临时参数
    uint64 uargv, uarg;

    argaddr(1, &uargv);
    // 处理文件路径到path中
    if (argstr(0, path, MAXPATH) < 0)
        return -1;

    memset(argv, 0, sizeof(argv));
    // 处理参数，复制到argv[]中
    for (i = 0;; i++) {
        if (i >= NELEM(argv))
            goto bad;
        if (fetchaddr(uargv+sizeof(uint64)*i, (uint64*)&uarg) < 0)
            goto bad;
        if (uarg == 0) {
            argv[i] = 0;
            break;
        }
        argv[i] = kalloc();
        if (argv[i] == 0)
            goto bad;
        if (fetchstr(uarg, argv[i], PGSIZE) < 0)
            goto bad;
    }

    int ret = exec(path, argv);

    for (i = 0; i < NELEM(argv) && argv[i] != 0; i++)
        kfree(argv[i]);

    return ret;

bad:
    for (i = 0; i < NELEM(argv) && argv[i] != 0; i++)
        kfree(argv[i]);
    return -1;
}